package client

import (
	"encoding/json"
	"frp/src/frp/models/consts"
	"frp/src/frp/models/msg"
	"frp/src/frp/utils/conn"
	"frp/src/frp/utils/log"
)

type ProxyClient struct {
	Name      string // 代理名称
	Passwd    string // 密码
	LocalIp   string // IP
	LocalPort int64  // 本地端口
}

// 创建一个本地连接
func (p *ProxyClient) GetLocalConn() (c *conn.Conn, err error) {
	c, err = conn.ConnectServer(p.LocalIp, p.LocalPort)
	if err != nil {
		log.Error("ProxyName [%s], connect to local port error, %v", p.Name, err)
	}

	return
}

// 创建一个远程连接
func (p *ProxyClient) GetRemoteConn(addr string, port int64) (c *conn.Conn, err error) {
	defer func() {
		if err != nil {
			c.Close()
		}
	}()

	// 建立连接
	c, err = conn.ConnectServer(addr, port)
	if err != nil {
		log.Error("ProxyName [%s], connect to server [%s:%d] error, %v", p.Name, addr, port, err)
		return
	}

	// 发送密码信息 验证本次连接
	req := msg.ClientCtlReq{
		Type:      consts.WorkConn,
		ProxyName: p.Name,
		Passwd:    p.Passwd,
	}

	buf, _ := json.Marshal(req)
	// send request
	err = c.Write(string(buf) + "\n")
	if err != nil {
		log.Error("ProxyName [%s], write to server error, %v", p.Name, err)
		return
	}

	err = nil
	return
}

// 开启信息流转
func (p *ProxyClient) StartTunnel(serverAddr string, serverPort int64) (err error) {
	// local control connection
	localConn, err := p.GetLocalConn()
	if err != nil {
		return
	}

	// remote control connection
	remoteConn, err := p.GetRemoteConn(serverAddr, serverPort)
	if err != nil {
		return
	}

	log.Warn("join two conns, (l[%s] r[%s]) (l[%s] r[%s])",
		localConn.GetLocalAddr(), localConn.GetRemoteAddr(),
		remoteConn.GetLocalAddr(), remoteConn.GetRemoteAddr(),
	)

	// 信息流转\转发
	go conn.Join(localConn, remoteConn)

	return nil
}
